﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace WorkFlowCore.EventBus
{
    public class DefaultEventBus : IEventBus
    {
        private IServiceProvider serviceProvider;
        private static object objLock = new object();

        public DefaultEventBus(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }

        private static Dictionary<Type, List<Type>> eventSubscribes;
        static DefaultEventBus()
        {
            eventSubscribes = new Dictionary<Type, List<Type>>();
        }

        private static void Subscribe(Type eventDataType, Type handlerType)
        {
            lock (objLock)
            {
                if (!eventSubscribes.ContainsKey(eventDataType))
                    eventSubscribes.Add(eventDataType, new List<Type> { });
            }

            eventSubscribes[eventDataType].Add(handlerType);


        }

        private static void Unsubscribe(Type eventDataType, Type handlerType)
        {
            if (!eventSubscribes.ContainsKey(eventDataType)) return;

            if (eventSubscribes[eventDataType].Contains(handlerType))
                eventSubscribes[eventDataType].Remove(handlerType);
        }

        public static void Subscribe<TData, THandler>() where THandler : IEventHandler<TData> where TData:BaseEventData
        {
            Subscribe(typeof(TData), typeof(THandler));
        }
        public static void Subscribe<EventHandler>() where EventHandler : IEventHandler
        {
            var handlerType = typeof(EventHandler);
            Subscribe(handlerType);
        }

        public static void Subscribe(Type handlerType)
        {
            var interfaceType = handlerType.GetInterfaces().FirstOrDefault(i => i.IsGenericType);
            if (interfaceType != null)
            {
                var dataType = interfaceType.GetGenericArguments()[0];
                Subscribe(dataType, handlerType);
            }
            else throw new Exception($"{handlerType.FullName} 需实现 {typeof(IEventHandler<>).FullName}");
        }



        /// <summary>
        /// 从 程序集注册
        /// </summary>
        /// <param name="assemblies"></param>
        public static void RegistSubscriptions(params Assembly[] assemblies)
        {
            foreach (var assembly in assemblies)
            {
                var types = assembly.GetTypes().Where(t => typeof(IEventHandler).IsAssignableFrom(t));

                foreach (var type in types)
                {
                    Subscribe(type);
                }
            }
        }

        public void Trigger<TData>(TData data)
        {
            var eventDataType =typeof(TData);
            if (!eventSubscribes.ContainsKey(eventDataType)) return;
            var handlerTypes = eventSubscribes[eventDataType];
            handlerTypes.ForEach(handlerType =>
            {
                using(var scope = serviceProvider.CreateScope())
                {
                    var handler = scope.ServiceProvider.GetService(handlerType);
                    handlerType.GetMethod("Handle", new Type[] { eventDataType }).Invoke(handler, new object[] { data });
                }
               
            });
        }

        public void SubscribeEventHandler(Type eventDataType, Type handlerType)
        {
            Subscribe(eventDataType, handlerType);
        }

        public void SubscribeEventHandler<TData, THandler>() where THandler : IEventHandler<TData> where TData : BaseEventData
        {
            Subscribe<TData, THandler>();
        }

        public void UnsubscribeEventHandler(Type eventDataType, Type handlerType)
        {
            Unsubscribe(eventDataType, handlerType);
        }

        public void UnsubscribeEventHandler<TData, THandler>() where THandler : IEventHandler<TData> where TData : BaseEventData
        {
            Unsubscribe(typeof(TData), typeof(THandler));
        }
    }
}
